package json

import (
	"fmt"
	"reflect"
	"strings"
)

func Marshal(v interface{}) ([]byte, error) { //递归地调用不同处理函数以实现Marshal功能
	if v == nil {
		return []byte("null"), nil
	}
	getValue := reflect.ValueOf(v)
	switch getValue.Type().Kind() { //根据传入类型映射到不同类型
	case reflect.Slice, reflect.Array:
		return arrayMarshal(v)
	case reflect.Struct:
		return structMarshal(v)
	case reflect.Ptr:
		return ptrMarshal(v)
	case reflect.Map:
		return mapMarshal(v)
	default:
		return basicMarshal(v)
	}
}

func arrayMarshal(v interface{}) ([]byte, error) { //数组类型
	var str strings.Builder
	str.WriteByte('[')
	getValue := reflect.ValueOf(v)
	for i := 0; i < getValue.Len(); i++ {
		if i > 0 {
			str.WriteByte(',')
		}
		v := getValue.Index(i)
		b, e := Marshal(v.Interface())
		if e != nil {
			return nil, e
		}
		str.Write(b)
	}
	str.WriteByte(']')
	return []byte(str.String()), nil
}

func structMarshal(v interface{}) ([]byte, error) { //结构体类型
	var str strings.Builder
	str.WriteByte('{')
	getValue := reflect.ValueOf(v)
	f := true
	for i := 0; i < getValue.NumField(); i++ {
		if f {
			f = false
		} else {
			str.WriteByte(',')
		}
		field := getValue.Type().Field(i)
		v, t := field.Tag.Lookup("mytag")
		if t {
			str.WriteString("\"" + v + "\":")
		} else {
			str.WriteString("\"" + field.Name + "\":")
		}
		b, err := Marshal(getValue.Field(i).Interface())
		if err != nil {
			return nil, err
		}
		str.Write(b)
	}
	str.WriteByte('}')
	return []byte(str.String()), nil
}

func ptrMarshal(v interface{}) ([]byte, error) { //指针类型
	getValue := reflect.ValueOf(v)
	return Marshal(getValue.Elem().Interface())
}

func mapMarshal(v interface{}) ([]byte, error) { //图类型
	var str strings.Builder
	str.WriteByte('{')
	getValue := reflect.ValueOf(v)
	it := getValue.MapRange()
	f := true
	for it.Next() {
		if f {
			f = false
		} else {
			str.WriteByte(',')
		}
		b, e := Marshal(it.Key().Interface())
		if e != nil {
			return nil, e
		}
		str.Write(b)
		str.WriteByte(':')
		b, e = Marshal(it.Value().Interface())
		if e != nil {
			return nil, e
		}
		str.Write(b)
	}
	str.WriteByte('}')
	return []byte(str.String()), nil
}

func basicMarshal(v interface{}) ([]byte, error) { //其他类型
	getValue := reflect.ValueOf(v)
	if getValue.Type().Kind() == reflect.String {
		return []byte("\"" + getValue.String() + "\""), nil
	}
	str := fmt.Sprintf("%v", getValue.Interface())
	return []byte(str), nil
}

func JsonMarshal(v interface{}) ([]byte, error) { //将golang对象转换成json字符串
	return Marshal(v) //返还json字符串的字符流或错误
}
